package com.loooooo.pm2024.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.Properties;

@Service
public class RedisUtils {
    @Autowired
    private StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();

    public static final String PREFIX = "pm2024:";
    @Autowired
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

    public void set(String key, String value, Duration duration) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        stringRedisTemplate.opsForValue().set(key, value, duration);
    }

    public void set(String key, float value, Duration duration) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        redisTemplate.opsForValue().set(key, value, duration);
    }

    public void set(String key, Object value, Duration duration) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        redisTemplate.opsForValue().set(key, value, duration);
    }

    public void setWithExpire(String key, Object value, Duration duration) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        redisTemplate.opsForValue().set(key, value, duration);
        redisTemplate.expire(key, duration);
    }

    public String pull(String key) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        String v = stringRedisTemplate.opsForValue().get(key);
        stringRedisTemplate.delete(key);
        return v;
    }

    public String get(String key, boolean remove) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        String v = stringRedisTemplate.opsForValue().get(key);
        if (remove) stringRedisTemplate.delete(key);
        return v;
    }

    public String get(String key) {
        return get(key, false);
    }

    public Object getObject(String key) {
        if (!key.startsWith(PREFIX)) key = PREFIX + key;
        return redisTemplate.opsForValue().get(key);
    }

    public Object getAbsObject(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    //向通道发送消息的方法
    public void sendChannelMessage(String channel, String message) {
        stringRedisTemplate.convertAndSend(channel, message);
    }

    public boolean lock(String key, String value, Duration duration) {
        return stringRedisTemplate.opsForValue().setIfAbsent(key, value, duration);
    }


    public boolean lock(String key, String value) {
        return stringRedisTemplate.opsForValue().setIfAbsent(key, value);
    }

    public boolean unlock(String key) {
        return stringRedisTemplate.delete(key);
    }

    //防止因为业务没有按时完成，锁提前失效后删除了其它线程加的锁
    public boolean unlock(String key, String value) {
        String v = stringRedisTemplate.opsForValue().get(key);

        if (v != null && v.equalsIgnoreCase(value)) {
            return stringRedisTemplate.delete(key);
        }
        return true;
    }
    public void keyExpiration() {
        //stringRedisTemplate.getConnectionFactory().getConnection().pSubscribe(null,"pSubscribe");
    }
    public int uptimeDays() {

        Properties info = stringRedisTemplate.getRequiredConnectionFactory().getConnection().info("Server");
        return Integer.parseInt(info.getProperty("uptime_in_days"));
    }


    public static String generateKey(Object target, Method method, Object... params) {
        StringBuilder sb = new StringBuilder();
        //sb.append(target.getClass().getName());
        sb.append(method.getName());
        for (Object obj : params) {
            if (obj == null) sb.append("/null");
            else {
                if (obj instanceof Serializable) {
                    sb.append("/" + obj.getClass().getSimpleName());
                    if (obj.toString().length() > 36) {
                        sb.append("=" + md5If(obj.toString()));
                    } else {
                        sb.append("=" + obj);
                    }
                } else {
                    sb.append("/" + obj);
                }
            }
        }
        return sb.toString();
    }


    static MessageDigest md;

    static {
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    private static String md5If(String text) {
        if (text == null) return text;
        //MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] md5 = md.digest(text.getBytes(StandardCharsets.UTF_8));
        StringBuffer buf = new StringBuffer("");
        for (int offset = 0; offset < md5.length; offset++) {
            int i = md5[offset];
            if (i < 0)
                i += 256;
            if (i < 16)
                buf.append("0");
            buf.append(Integer.toHexString(i));
        }
        return buf.toString();

    }

    public static class MyKeyExpirationEventMessageListener extends KeyExpirationEventMessageListener{

        public MyKeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
            super(listenerContainer);
        }
    }
}
